// vim: set et sw=4 sts=4 cindent:
/*
 * @File: estimator.h
 *
 * @Abstract: Public interface for the rate estimator.
 *
 * @Notes:
 *
 * @@-COPYRIGHT-START-@@
 *
 * Copyright (c) 2015-2017 Qualcomm Technologies, Inc.
 *
 * All Rights Reserved.
 * Confidential and Proprietary - Qualcomm Technologies, Inc.
 *
 * 2015-2016 Qualcomm Atheros, Inc.
 *
 * All Rights Reserved.
 * Qualcomm Atheros Confidential and Proprietary.
 *
 * @@-COPYRIGHT-END-@@
 */

#ifndef estimator__h
#define estimator__h

#include "lbd_types.h"  // for LBD_STATUS and other type defs
#include "stadb.h"
#include "steerexec.h"

#if defined(__cplusplus)
extern "C" {
#endif

/**
 * @brief Events generated by this module to signal completion of the
 *        estimation logic.
 */
typedef enum estimator_event_e {
    /// All estimates are available for a single STA are complete.
    estimator_event_staDataMetricsComplete,

    /// All estimates for airtime of STAs on a given channel are complete.
    estimator_event_perSTAAirtimeComplete,

    /// Detected that a STA is suffering from interference
    estimator_event_staInterferenceDetected,

    /// At least one polluted BSS for a STA was marked as no longer polluted.
    estimator_event_staPollutionCleared,

    /// Request Legacy Steering for 11k Max consecutive failed client.
    estimator_event_requestLegacySteering11kSta,

    estimator_event_maxnum
} estimator_event_e;

/**
 * @brief Reason code to indicate why pollution state changed for a given STA
 */
typedef enum estimatorPollutionChangedReason_e {
    /// Pollution state chagned based on detection result.
    estimatorPollutionChangedReason_detection,

    /// Pollution state cleared due to aging.
    estimatorPollutionChangedReason_aging,

    /// Pollution state changed due to report from remote node
    estimatorPollutionChangedReason_remote,

    /// Invalid reason
    estimatorPollutionChangedReason_invalid
} estimatorPollutionChangedReason_e;

/**
 * @brief The format of the estimator_event_staDataMetricsComplete event.
 */
typedef struct estimator_staDataMetricsCompleteEvent_t {
    /// Address of the STA for which capacity and airtime estimates are
    /// complete.
    struct ether_addr addr;

    /// Whether the measurement of STA data metrics succeeded or not.
    LBD_STATUS result;

    /// The trigger to this data metrics estimation
    steerexec_reason_e trigger;

    /// The channel measured in 802.11k beacon report
    lbd_channelId_t measuredChannel;

    /// The local BSS reported in 802.11k beacon report.
    /// If none, will report an invalid BSS with invalid channel number
    lbd_bssInfo_t measuredLocalBSS;
} estimator_staDataMetricsCompleteEvent_t;

/**
 * @brief The format of the estimator_event_perSTAAirtimeComplete event.
 */
typedef struct estimator_perSTAAirtimeCompleteEvent_t {
    /// The channel on which the estimate is now complete.
    lbd_channelId_t channelId;

    /// The number of STAs for which an airtime was estimated.
    size_t numSTAsEstimated;
} estimator_perSTAAirtimeCompleteEvent_t;

/**
 * @brief The format of the estimator_event_staInterferenceDetected event.
 */
typedef struct estimator_staInterferenceDetectedEvent_t {
    /// Address of the STA for which interference was detected.
    struct ether_addr addr;
} estimator_staInterferenceDetectedEvent_t;

/**
 * @brief The format of the estimator_event_staPollutionCleared event.
 */
typedef struct estimator_staPollutionClearedEvent_t {
    /// Address of the STA for which pollution was cleared.
    struct ether_addr addr;
} estimator_staPollutionClearedEvent_t;

/**
 * @brief Function callback type that other modules can register to be
 *        informed when data metrics can be measured again for a given entry.
 *
 * The callback occurs after the entry has been updated.
 *
 * @param [in] handle  the entry that was updated
 * @param [in] cookie  the value provided by the caller when the observer
 *                     callback function was registered
 */
typedef void (*estimator_staDataMetricsAllowedObserverCB)(
        stadbEntry_handle_t handle, void *cookie);

/**
 * @brief Initialize the estimator module.
 *
 * @return LBD_OK on success; otherwise LBD_NOK
 */
LBD_STATUS estimator_init(void);

/**
 * @brief Deinitialize the station monitor module
 *
 * @return LBD_OK on success; otherwise LBD_NOK
 */
LBD_STATUS estimator_fini(void);

/**
 * @brief Take the serving channel uplink RSSI and estimate the non-serving
 *        channels if necessary.
 *
 * The serving channel RSSI is assumed to be valid and recent. The uplink
 * RSSI will only be updated if it is not already valid based on probe
 * request measurements.
 *
 * @param [in] handle  the entry to update
 *
 * @return LBD_OK on success; otherwise LBD_NOK
 */
LBD_STATUS estimator_estimateNonServingUplinkRSSI(stadbEntry_handle_t handle);

/**
 * @brief Retrieve the consecutive 11k failure count.
 *
 * @param [in] handle  the handle of the STA for which to perform the estimate
 *
 * @return LBD_TRUE if max consecutive 11k failure count is reached
 *                  else return LBD_FALSE.
 */
LBD_BOOL estimator_estimateMaxConsecutive11kFailure(stadbEntry_handle_t handle);

/**
 * @brief Compute capacity and airtime information for the STA on both the
 *        serving and non-serving channels.
 *
 * This will result in the entry's serving channel full capacity, last data rate
 * and airtime information being updated. On the non-serving channel, an
 * estimated capacity and airtime will be stored. Once both of these are
 * complete, a estimator_event_staDataMetricsComplete will be generated.
 *
 * @param [in] handle  the handle of the STA for which to perform the estimate
 * @param [in] trigger  the trigger of capacity and airtime estimation
 *
 * @return LBD_OK on success; otherwise LBD_NOK
 */
LBD_STATUS estimator_estimateSTADataMetrics(stadbEntry_handle_t handle,
                                            steerexec_reason_e trigger);

/**
 * @brief Estimate the airtime of each STA active on the given channel that
 *        is a candidate for active steering.
 *
 * This will result in each entry's full capacity, last data rate, and airtime
 * information being updated. Once this is complete, an
 * estimator_event_perSTAAirtimeComplete event will be generated.
 *
 * @param [in] channelId  the channel on which to do the estimates
 *
 * @return LBD_OK on success; otherwise LBD_NOK
 */
LBD_STATUS estimator_estimatePerSTAAirtimeOnChannel(lbd_channelId_t channelId);

/**
 * @brief Register a function to get called back when an entry is now
 *        eligible again for an estimate of its data metrics.
 *
 * In other words, when the callback occurs,
 * estimator_estimateSTADataMetrics() is expected to succeed.
 *
 * @param [in] callback  the callback function to invoke
 * @param [in] cookie  the parameter to pass to the callback function
 *
 * @return LBD_OK on success; otherwise LBD_NOK
 */
LBD_STATUS estimator_registerSTADataMetricsAllowedObserver(
        estimator_staDataMetricsAllowedObserverCB callback, void *cookie);

/**
 * @brief Unregister the observer callback function.
 *
 * @param [in] callback  the callback function to unregister
 * @param [in] cookie  the parameter for the callback provided when
 *                     registering
 *
 * @return LBD_OK on success; otherwise LBD_NOK
 */
LBD_STATUS estimator_unregisterSTADataMetricsAllowedObserver(
        estimator_staDataMetricsAllowedObserverCB callback, void *cookie);

// ====================================================================
// Constants needed by test cases
// ====================================================================

// These need not be exposed but it is useful to do so for unit tests to
// avoid duplicating the strings.

#define ESTIMATOR_AGE_LIMIT_KEY                    "AgeLimit"
#define ESTIMATOR_RSSI_DIFF_EST_W5_FROM_W2_KEY     "RSSIDiff_EstW5FromW2"
#define ESTIMATOR_RSSI_DIFF_EST_W2_FROM_W5_KEY     "RSSIDiff_EstW2FromW5"
#define ESTIMATOR_PROBE_COUNT_THRESHOLD_KEY        "ProbeCountThreshold"
#define ESTIMATOR_STATS_SAMPLE_INTERVAL_KEY        "StatsSampleInterval"
#define ESTIMATOR_MAX_11K_RESPONSE_TIME_KEY        "Max11kResponseTime"
#define ESTIMATOR_MAX_11K_UNFRIENDLY_KEY           "Max11kUnfriendly"
#define ESTIMATOR_11K_PROHIBIT_TIME_SHORT_KEY      "11kProhibitTimeShort"
#define ESTIMATOR_11K_PROHIBIT_TIME_LONG_KEY       "11kProhibitTimeLong"
#define ESTIMATOR_PHY_RATE_SCALING_FOR_AIRTIME_KEY "PhyRateScalingForAirtime"
#define ESTIMATOR_ENABLE_CONTINUOUS_THROUGHPUT_KEY "EnableContinuousThroughput"
#define ESTIMATOR_MAX_POLLUTION_TIME_KEY           "MaxPollutionTime"
#define ESTIMATOR_FAST_POLLUTION_BUFSIZE_KEY       "FastPollutionDetectBufSize"
#define ESTIMATOR_NORMAL_POLLUTION_BUFSIZE_KEY     "NormalPollutionDetectBufSize"
#define ESTIMATOR_POLLUTION_DETECT_THRESHOLD_KEY   "PollutionDetectThreshold"
#define ESTIMATOR_POLLUTION_CLEAR_THRESHOLD_KEY    "PollutionClearThreshold"
#define ESTIMATOR_INTERFERENCE_AGE_LIMIT_KEY       "InterferenceAgeLimit"
#define ESTIMATOR_IAS_LOW_RSSI_THRESHOLD_KEY       "IASLowRSSIThreshold"
#define ESTIMATOR_IAS_MAX_RATE_FACTOR_KEY          "IASMaxRateFactor"
#define ESTIMATOR_IAS_MIN_DELTA_BYTES_KEY          "IASMinDeltaBytes"
#define ESTIMATOR_IAS_MIN_DELTA_PACKETS_KEY        "IASMinDeltaPackets"
#define ESTIMATOR_IAS_ENABLE_SINGLE_BAND_DETECT_KEY "IASEnableSingleBandDetect"

#define ESTIMATOR_IAS_CURVE_24G_20M_1SS "IASCurve_24G_20M_1SS"
#define ESTIMATOR_IAS_CURVE_24G_20M_2SS "IASCurve_24G_20M_2SS"
#define ESTIMATOR_IAS_CURVE_5G_40M_1SS "IASCurve_5G_40M_1SS"
#define ESTIMATOR_IAS_CURVE_5G_40M_2SS "IASCurve_5G_40M_2SS"
#define ESTIMATOR_IAS_CURVE_5G_80M_1SS "IASCurve_5G_80M_1SS"
#define ESTIMATOR_IAS_CURVE_5G_80M_2SS "IASCurve_5G_80M_2SS"

#define ESTIMATOR_CURVE_COEF_D0(curveType) curveType "_d0"
#define ESTIMATOR_CURVE_COEF_RSSI_D1(curveType) curveType "_rd1"
#define ESTIMATOR_CURVE_COEF_MCS_D1(curveType) curveType "_md1"
#define ESTIMATOR_CURVE_COEF_RSSI_D2(curveType) curveType "_rd2"
#define ESTIMATOR_CURVE_COEF_RSSI_MCS_D1(curveType) curveType "_rmd1"
#define ESTIMATOR_CURVE_COEF_MCS_D2(curveType) curveType "_md2"


#if defined(LBD_DBG_MENU) && defined(GMOCK_UNIT_TESTS)
struct cmdContext;

/**
 * @brief Request the status to be dumped for all STAs.
 *
 * @param [in] context  the output context
 * @param [in] cmd  the command in the debug CLI
 */
void estimatorMenuStatusHandler(struct cmdContext *context, const char *cmd);

/**
 * @brief Request a rate estimate for a STA.
 *
 * @param [in] context  the output context
 * @param [in] cmd  the command in the debug CLI
 */
void estimatorMenuRateHandler(struct cmdContext *context, const char *cmd);

/**
 * @brief Request an airtime estimate be done on a given channel.
 *
 * @param [in] context  the output context
 * @param [in] cmd  the command in the debug CLI
 */
void estimatorMenuAirtimeHandler(struct cmdContext *context, const char *cmd);

/**
 * @brief Turn on/off the debug mode for estimator (currently limited to
 *        the interference detection cases).
 *
 * @param [in] context  the output context
 * @param [in] cmd  the command in the debug CLI
 */
void estimatorMenuDebugHandler(struct cmdContext *context, const char *cmd);

/**
 * @brief Inject an event that a given STA is being impacted by interference
 *        or not.
 *
 * @param [in] context  the output context
 * @param [in] cmd  the command in the debug CLI
 */
void estimatorMenuInterferenceDetectedHandler(struct cmdContext *context,
                                              const char *cmd);

/**
 * @brief Inject fake statistics to evaluate interference
 *
 * @param [in] context  the output context
 * @param [in] cmd  the command in the debug CLI
 */
void estimatorMenuInterferenceStatsHandler(struct cmdContext *context,
                                           const char *cmd);

/**
 * @brief Trigger diaglog from the debug CLI
 *
 * @param [in] context  the output context
 * @param [in] cmd  the command in the debug CLI
 */
void estimatorMenuDiaglogHandler(struct cmdContext *context, const char *cmd);

#endif /* LBD_DBG_MENU && GMOCK_UNIT_TESTS */

#if defined(__cplusplus)
}
#endif

#endif // estimator__h

